【新機能】BigQuery で GROUP BY と SELECT DISTINCT が ARRAY と STRUCT にも使えるようになりました

【新機能】BigQuery で GROUP BY と SELECT DISTINCT が ARRAY と STRUCT にも使えるようになりました

Clock Icon2024.08.29

Google Cloud データエンジニアのはんざわです。
2024年8月29日のアップデートにより、ARRAY 型と STRUCT 型にも GROUP BYSELECT DISTINCT が使えるようになりました。

August 28, 2024

You can now use the GROUP BY clause and the SELECT DISTINCT clause with the ARRAY and STRUCT data types. This feature is in Preview.

本ブログでは、さっそくその使い方を紹介したいと思います。

このアップデートの何が嬉しいの?

GROUP BYSELECT DISTINCT のそれぞれのケースで、従来のクエリとどのように変わるのかを見てみましょう。

GROUP BY

これまでは、ARRAY 型に集約関数を使用したい場合、一度 ARRAY 型を文字列に変換してから集約関数を実行する必要がありました。

今後はそのような前処理をする必要がなくなり、よりシンプルなクエリで集約関数を使用することが可能になりました。

これまで
WITH sample AS (
  SELECT ['A', 'B', 'C'] AS arr, 3 AS cnt
  UNION ALL
  SELECT  ['D', 'E', 'F'] AS arr, 2 AS cnt
  UNION ALL
  SELECT  ['A', 'B', 'C'] AS arr, 5 AS cnt
)

SELECT
  ARRAY_TO_STRING(arr, ','),
  SUM(cnt) AS sum_cnt
FROM
  sample
GROUP BY arr
これから
WITH sample AS (
  SELECT ['A', 'B', 'C'] AS arr, 3 AS cnt
  UNION ALL
  SELECT ['D', 'E', 'F'] AS arr, 2 AS cnt
  UNION ALL
  SELECT ['A', 'B', 'C'] AS arr, 5 AS cnt
)

SELECT
  arr,
  SUM(cnt) AS sum_cnt
FROM
  sample
GROUP BY arr

また、 STRUCT 型も同様に簡潔なクエリで集約関数を実行することができるようになりました。
従来は、STRUCT 型のフィールドから一意になるようなキーの組み合わせを抽出して集約関数を実行する必要がありましたが、今後は不要になると思われます。

これまで
WITH sample AS (
  SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 3 AS cnt
  UNION ALL
  SELECT STRUCT(2 AS id, 'banana' AS name) AS f_struct, 2 AS cnt
  UNION ALL
  SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 5 AS cnt
)

SELECT
  f_struct.id,
  SUM(cnt) AS sum_cnt
FROM
  sample
GROUP BY f_struct.id
これから
WITH sample AS (
  SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 3 AS cnt
  UNION ALL
  SELECT STRUCT(2 AS id, 'banana' AS name) AS f_struct, 2 AS cnt
  UNION ALL
  SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 5 AS cnt
)

SELECT
  f_struct,
  SUM(cnt) AS sum_cnt
FROM
  sample
GROUP BY f_struct

SELECT DISTINCT

これまでもテーブルの一意判定を行う際に SELECT DISTINCT を使用していましたが、ARRAY 型や STRUCT 型のデータが含まれていると使用することができませんでした。
その対処法として、主キーと QUALIFY でユニーク化するなど、別のアプローチを取る必要がありました。

しかし、DISTINCTARRAY 型と STRUCT 型にも対応したことで、今までよりもシンプルなクエリでテーブルをユニーク化することが可能になりました。

これまで
WITH sample AS (
  SELECT 1 AS id, [1, 2, 3] AS arr
  UNION ALL
  SELECT 2 AS id, [4, 5, 6] AS arr
  UNION ALL
  SELECT 1 AS id, [1, 2, 3] AS arr
)

SELECT
  *
FROM
  sample
QUALIFY ROW_NUMBER() OVER(PARTITION BY id) = 1
これから
WITH sample AS (
  SELECT 1 AS id, [1, 2, 3] AS arr
  UNION ALL
  SELECT 2 AS id, [4, 5, 6] AS arr
  UNION ALL
  SELECT 1 AS id, [1, 2, 3] AS arr
)

SELECT
  DISTINCT *
FROM
  sample

関連の機能も検証してみる

今回のアップデートに関連して、いくつか気になる点があったため、検証してみました。
検証項目は以下の通りです。

  1. EXCEPT DISTINCT は使えるのか
  2. JSON 型でも使えるのか

1. EXCEPT DISTINCT は使えるのか

結論として、EXCEPT DISTINCT はまだ使えないようです。。。

SELECT [1, 2, 3] AS arr, 1 AS cnt
EXCEPT DISTINCT
SELECT [1, 2, 3] AS arr, 1 AS cnt

> Type ARRAY is not supported in INTERSECT DISTINCT or EXCEPT DISTINCT operation

以下のブログでも紹介されているように、EXCEPT DISTINCT を使用することで複数のテーブルの一致判定を行うことができますが、この方法には問題があります。

しかし、この方法には問題があり、ARRAYSTRUCT 型には対応していないため、別のアプローチを取る必要がありました。

EXCEPT DISTINCT を 2 つのテーブルで双方向に行い、対称差を求めます。対称差が存在しなければ、一致していると見なすことができます。

しかし、Groupable でない型 ARRAY, STRUCT, GEOGRAPHY には対応できない問題があります

https://queuery.com/blog/2020/01/26/two-tables-have-exactly-the-same-data-in-bigquery/

ARRAYSTRUCT 型には対応していないため、別のアプローチを取る必要がありましたが、今後のアップデートで EXCEPT DISTINCT がこれらの型にも対応することを期待しています。

2. JSON でも使えるのか

残念ながら、こちらも使えないようです。。。

WITH sample AS (
  SELECT JSON '{"key": "apple"}' AS json_o
  UNION ALL
  SELECT JSON '{"key": "apple"}' AS json_o
)

SELECT 
  DISTINCT json_o
FROM
  sample

> Column json_o of type JSON cannot be used in SELECT DISTINCT

筆者は、STRUCT 型があまり好きではないため、代わりに JSON 型を採用しています。
JSON 型のテーブルも、STRUCT 型と同様に主キーと QUALIFY を使ってユニーク化することが多いので、JSON 型でも SELECT DISTINCT が実行できるようになると嬉しいなーと思いました。
(とはいえ、JSON 型はキーの順序が一定でないため、難しいかもしれませんが...)

まとめ

本ブログでは、新たにプレビュー機能となった ARRAY 型と STRUCT 型に対する GROUP BYSELECT DISTINCT の使用方法を試してみました。

最近プレビューに追加された JSON_KEYS の機能もそうですが、地味ながらも便利なアップデートが続いている印象です。
このような痒い所に手が届く機能がどんどん追加されることは、筆者として非常に嬉しい限りです。

今後のアップデートにも期待が高まります。

https://dev.classmethod.jp/articles/gcp-bigquery-json-object-keys/

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.